/**
 * MCU 适配头文件
 * Copyright (c) 2021 深圳市智辰科技有限公司
 * All rights reserved.
 */

#include "_base.h"

#ifdef __cplusplus
extern "C" {
#endif


/// FR801xH 是小端模式
#define __LITTLE_ENDIAN__ 1

/// 从一个流中获取一个指针
#define getPointer(stream) (*((void**)stream))

// 字节序转换函数
// 网络字节顺序采用 big endian 排序方式
// 所以如果 MCU 的字节序是 little endian 方式时，需要进行转换
#if (__LITTLE_ENDIAN__ == 1)
	#define le2h16(w)   (w)
	#define le2h32(dw)  (dw)
	#define be2h16(w)   BL16(w)
	#define be2h32(dw)  BL32(dw)
					    
	#define h2le16(w)   (w)
	#define h2le32(dw)  (dw)
	#define h2be16(w)   BL16(w)
	#define h2be32(dw)  BL32(dw)

	#define ntoh32(dw) 	BL32(dw)
	#define ntoh16(w) 	BL16(w)
	#define hton32(dw) 	BL32(dw)
	#define hton16(w) 	BL16(w)
#else
	#define le2h16(w)   BL16(w)
	#define le2h32(dw)  BL32(dw)
	#define be2h16(w)   (w)
	#define be2h32(dw)  (dw)
					    
	#define h2le16(w)   BL16(w)
	#define h2le32(dw)  BL32(dw)
	#define h2be16(w)   (w)
	#define h2be32(dw)  (dw)
	
	#define ntoh32(dw) 	(dw)
	#define ntoh16(w) 	(w)
	#define hton32(dw) 	(dw)
	#define hton16(w) 	(w)
#endif

// 从一个字节流中，以大端模式读取32/16位整数(无符号/有符号)，解决字节对齐问题，同时解决字节序问题
uint32_t getBeU32(const void *stream);
uint16_t getBeU16(const void *stream);
#define getBeS32(stream) ((s32)getBeU32(stream))
#define getBeS16(stream) ((s16)getBeU16(stream))

// 从一个字节流中，以小端模式读取32/16位整数(无符号/有符号)，解决字节对齐问题，同时解决字节序问题
uint32_t getLeU32(const void *stream);
uint16_t getLeU16(const void *stream);
#define getLeS32(stream) ((s32)getLeU32(stream))
#define getLeS16(stream) ((s16)getLeU16(stream))

/// RAM 起始地址
#define MCU_RAM_BEGIN_ADDRESS   0x20000000
/// Flash 起始地址
#define MCU_FLASH_BEGIN_ADDRESS 0x01000000

/**
各个型号的芯片 Flash/RAM 大小
+-------+-----------+-----------+----------+----------+----------+----------+---------+
| 型号  | FR8012HBS | FR8012HAS | FR8012HA | FR8016HA | FR8016HD | FR8018HA | FR8018H |
+-------+-----------+-----------+----------+----------+----------+----------+---------+
| Flash |   256 KB  |   512 KB  |  512 KB  |  512 KB  |  1024 KB |  512 KB  | 外接SPI |
+-------+-----------+-----------+----------+----------+----------+----------+---------+
| RAM   |   48 KB   |   48 KB   |  48 KB   |  48 KB   |  48 KB   |  48 KB   |  48 KB  |
+-------+-----------+-----------+----------+----------+----------+----------+---------+
 */
#if   (defined MCU_TYPE_FR8012HBS)
  #define MCU_FLASH_SIZE	0x40000		// 256 KBytes
#elif (defined MCU_TYPE_FR8012HAS) || (defined MCU_TYPE_FR8012HA) || (defined MCU_TYPE_FR8016HA) || (defined MCU_TYPE_FR8018HA)
  #define MCU_FLASH_SIZE 	0x80000		// 512 KBytes
#elif (defined MCU_TYPE_FR8016HD)
  #define MCU_FLASH_SIZE 	0x100000	// 1024 KBytes
#else
  #error "Undefined MCU type for FLASH size !"
#endif

/// Flash 结束地址(有效区域为地址所指向的前一个字节)
#define MCU_FLASH_END_ADDRESS   (MCU_FLASH_BEGIN_ADDRESS + MCU_FLASH_SIZE)
// Flash 页面大小
#define MCU_FLASH_PAGE_SIZE 4096

/// 检查目标地址段是否处于 FLASH 中
bool mcu_is_in_flash(uint32_t addr, uint32_t len);

/// 计算目标地址所在的页地址
uint32_t mcu_flash_page_addr(uint32_t addr);

/// 数据块写入 FLASH (自动根据需要擦除并解决跨页写问题)
/// @param addr 目标地址，必须在 Flash 中
/// @param len 要写入的数据长度，必须在 Flash 中
/// @param data 要写入的数据
/// @return 返回写入的数据的有效长度
uint32_t mcu_flash_write(uint32_t addr, uint32_t len, void *data);

/// MCU 初始化
void mcu_init(void);

/// 获取 MCU 唯一标识
uint8_t* mcu_get_chip_id(void);

/// 获取 MCU VBAT 电压(mv)
uint16_t mcu_get_vbat(void);

/// 获取 PMU 中断状态(见 driver_pmu.c )
extern uint16_t pmu_get_isr_state(void);
#define mcu_get_pmu_isr_state() pmu_get_isr_state()

/// @brief 看门狗最大定时时间(ms)
#define MCU_WATCHDOG_MAX_TIMEOUT (MAXU32/32768)
/// @brief 初始化看门狗
/// @timeout 看门狗定时(ms)
void mcu_watchdog_init(uint32_t timeout);
/// @brief 看门狗停止
void mcu_watchdog_stop(void);
/// @brief 喂看门狗
void mcu_watchdog_feed(void);


#ifdef __cplusplus
}
#endif
